package jp.seraph.cui;

import java.util.ArrayList;
import java.util.List;

import jp.seraph.cui.message.MessageUtil;

/**
 * 標準的なCommandを表すCommandの抽象実装
 *
 *
 */
public abstract class AbstractCommand extends AbstractNode implements Command {
    public AbstractCommand(Mode aParent, InternalConsole aConsole) {
        super(aParent, aConsole);
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#setName(java.lang.String)
     */
    public void setName(String aName) {
        // 基本は何もしない
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#getChildren()
     */
    public List<SystemNode> getChildren() {
        return new ArrayList<SystemNode>();
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#getChildren(java.lang.Object)
     */
    public <E extends SystemNode> List<E> getChildren(E aDummy) {
        return new ArrayList<E>();
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#getChildren(jp.seraph.cui.SystemNodeType)
     */
    public List<SystemNode> getChildren(SystemNodeType aType) {
        return new ArrayList<SystemNode>();
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#getChildren(java.lang.Class)
     */
    public List<SystemNode> getChildren(Class<? extends SystemNode> aType) {
        return new ArrayList<SystemNode>();
    }

    /**
     *
     * @see jp.seraph.cui.SystemNode#getChild(java.lang.String)
     */
    public SystemNode getChild(String aName) {
        return null;
    }

    /**
     * 型チェックを行う実装
     *
     * @see jp.seraph.cui.Command#execute(jp.seraph.cui.SystemNode[])
     */
    public final void execute(SystemNode... aArgs) {
        SystemNodeType[][] tExpectedTypeArray = getArgumentTypes();
        int tCount = tExpectedTypeArray.length;

        for(int i=0; i<tCount; i++){
            SystemNodeType[] tArgTypes = tExpectedTypeArray[i];
            if(match(tArgTypes, aArgs)){
                executeImpl(aArgs, i);
                return;
            }
        }

        String[] tArgTypeList = new String[aArgs.length];
        for(int i=0; i<tArgTypeList.length; i++)
            tArgTypeList[i] = aArgs[i].getType().getName();

        throw new IllegalArgumentException(MessageUtil.argumentTypeMatchingError(this.getName(), tArgTypeList));
    }

    private boolean match(SystemNodeType[] aTypes, SystemNode[] aArgs){
        SystemNodeType[] tExpectedTypes = aTypes;

        if (tExpectedTypes.length != aArgs.length)
            return false;;

        int tCount = tExpectedTypes.length;
        for (int i = 0; i < tCount; i++) {
            SystemNodeType tExpected = tExpectedTypes[i];
            SystemNodeType tActual = aArgs[i].getType();
            if(!tActual.isCompatible(tExpected))
                return false;
        }

        return true;
    }

    protected abstract void executeImpl(SystemNode[] aArgs, int aArgListIndex);
}
